import type { DownloadTriggerConfig } from '../../../lib/document_operator/triggers/download_trigger'
import type { ComponentStyleIdType, PlatformTypeValue } from '../../../types/interfaces'
import { BaseModule } from '../../../lib/abstract'
import { DownloadTrigger } from '../../../lib/document_operator/triggers/download_trigger'
import { PageHandler } from '../../../lib/page_handler'
import {
  BIAN_LIST_ITEM_SELECTOR,
  BianPageType,
} from '../../../lib/page_handler/platform/bian/types'
import { ToolKit } from '../../../lib/utils/toolkit'
import {
  BodyAttrs,
  ComponentStyleId,
  HOSTNAME,
  logger,
  loggerDeduplicator,
  SUPPORTED_PLATFORMS,
} from '../../../types/constants'
import { SYMBOLS } from '../../../types/interfaces'
import { ConfigManager } from '../../config_manager'

export interface QuickDownloadConfig {
  selector: string
  detailSelector: {
    url: string
    downloadButton: string
  }
  needLogin?: boolean
}
export type QuickDownloadPlatformConfig = Partial<Record<PlatformTypeValue, Record<string, QuickDownloadConfig>>>

export interface QuickDownloadOptions {
  index: number
  imageName: string
  detailUrl: string
}

interface Config {
  enabled?: boolean
  hoverDelay?: number // 悬停延迟（毫秒）
  fetchConfig: {
    timeout: number
    retryCount: number
  }
}

export class QuickDownload extends BaseModule {
  // @Decorators.Identity
  readonly id: string = 'quick_download'
  get name(): ComponentStyleIdType {
    return 'QuickDownload'
  }

  // @Decorators.InheritedConfig
  readonly styleId: string = ComponentStyleId[this.name]
  readonly supportedPlatforms: string[] = ConfigManager.getInstance().moduleSupportedPlatforms(this.name)
  // @Decorators.PublicState
  isInitialized: boolean = false
  private static instance: QuickDownload
  // @Decorators.Dependency
  private readonly downloadTrigger: DownloadTrigger = new DownloadTrigger()
  // @Decorators.UIElement
  private readonly BUTTON_ID: string = 'quick-download-btn'
  private readonly PROCESSED_ATTR: string = `${BodyAttrs.PROCESSED_ELEMENT}-download`

  get currentConfig(): QuickDownloadConfig | undefined {
    return this.getCurrentConfig()
  }

  // @Decorators.TemporaryState
  private downloadQueue: Map<string, boolean> = new Map() // 防止重复下载
  private activeDownloads: Set<string> = new Set() // 正在进行的下载

  config: Config = {
    enabled: true,
    hoverDelay: 300,
    fetchConfig: {
      timeout: 10000,
      retryCount: 1,
    },
  }

  /**
   * 获取单例实例
   */
  public static getInstance(): QuickDownload {
    if (!QuickDownload.instance) {
      QuickDownload.instance = new QuickDownload()
    }
    return QuickDownload.instance
  }

  handleCleanupReferences(): void {
    this.downloadQueue.clear()
    this.activeDownloads.clear()
  }

  handleCleanupOthers(): void {
    this.unregisterStyle(this.styleId)

    if (!this.currentConfig)
      return

    const { selector } = this.currentConfig

    // 移除处理标识
    $(selector).removeAttr(this.PROCESSED_ATTR)
  }

  core(): void {
    this.loadConfig()

    if (!this.config.enabled)
      return

    this.applyToImages()

    // 注册样式
    this.registerStyle(this.styleId, this.getStyles())
  }

  onToggleCallback(_id: string, checked: boolean, first: boolean): void {
    super.onToggleCallback(_id, checked, first)
  }

  /**
   * 获取当前页面的配置
   */
  getCurrentConfig(): QuickDownloadConfig | undefined {
    const config: QuickDownloadPlatformConfig = {
      [SUPPORTED_PLATFORMS.BIAN]: {
        [BianPageType.List]: {
          selector: BIAN_LIST_ITEM_SELECTOR,
          detailSelector: {
            url: 'a:has(img)',
            downloadButton: '.side .downpic > a',
          },
          needLogin: true,
        },
      },
    }

    const currentConfig = config[HOSTNAME]?.[PageHandler.getCurrentPageType()]

    if (!currentConfig) {
      logger.warn(`[${this.name}] 未找到当前页面类型的配置`)
    }

    return currentConfig
  }

  private applyToImages(): void {
    if (!this.currentConfig)
      return

    const { selector } = this.currentConfig
    const $containers = $(selector)
    logger.info(`[${this.name}] 找到 ${$containers.length} 个图片容器`)

    $containers.each((index, container) => {
      this.attachToContainer($(container), index)
    })
  }

  /**
   * 为单个容器附加下载按钮
   */
  private attachToContainer($container: JQuery<Element>, index: number): void {
    // 检查是否已处理
    if ($container.attr(this.PROCESSED_ATTR))
      return

    const { detailSelector } = this.currentConfig!
    const $detailLink = $container.find(detailSelector.url)

    // 获取详情页链接
    const detailUrl = $detailLink.attr('href')
    const imageName = $detailLink.attr('title') || `图片 ${index + 1}`

    if (!detailUrl) {
      logger.warn(`[${this.name}] 未找到详情页链接`)
      return
    }

    // 附加下载按钮
    const $downloadBtn = this.attachDownloadButton($container, {
      index,
      imageName,
      detailUrl,
    })

    // 添加悬浮事件
    this.setupHoverEvents($container, $downloadBtn)

    // 标记为已处理
    $container.attr(this.PROCESSED_ATTR, 'true')
  }

  /**
   * 附加下载按钮到图片容器
   */
  private attachDownloadButton($container: JQuery<Element>, options: QuickDownloadOptions): JQuery<Element> | null {
    // 检查是否需要登录
    const needLogin = this.currentConfig?.needLogin || false
    if (needLogin && !ToolKit.browser.platform.isLoggedIn()) {
      loggerDeduplicator.warn(`[${this.name}] 用户未登录，跳过添加下载按钮`)
      return null
    }

    const { index, detailUrl } = options
    let $downloadBtn = $container.find(`.${this.BUTTON_ID}`)

    // 检查是否已存在按钮
    if ($downloadBtn.length > 0)
      return $downloadBtn

    // 确保容器有相对定位
    if ($container.css('position') === 'static')
      $container.css('position', 'relative')

    // 创建下载按钮
    $downloadBtn = $(`
        <a class="${this.BUTTON_ID}" 
          data-detail-url="${detailUrl}" 
          data-item-index="${index}"
          title="快速下载"
          style="opacity: 0">
          ${SYMBOLS.UI.DOWNLOAD}
        </a>
      `)

    $container.append($downloadBtn)

    // 添加点击事件
    const clickHandler = async (e: Event) => {
      e.preventDefault()
      e.stopPropagation()

      await this.handleDownloadClick($downloadBtn, options)
    }

    // 添加点击事件
    $downloadBtn.on('click', clickHandler)

    this.tracker.creation($downloadBtn)
    this.tracker.eventListeners($downloadBtn, 'click', clickHandler)
    ToolKit.browser.platform.markProjectElement($downloadBtn)

    return $downloadBtn
  }

  /**
   * 设置悬浮事件
   */
  private setupHoverEvents($container: JQuery<Element>, $button: JQuery<Element> | null): void {
    let hoverTimer: number | null = null

    const mouseEnterHandler = () => {
      hoverTimer = this.startHoverTimer(hoverTimer, $button)
    }

    const mouseLeaveHandler = () => {
      this.stopHoverTimer(hoverTimer)

      $button
        ?.removeClass('visible')
        .html($button.hasClass('downloaded')
          ? SYMBOLS.STATUS.SUCCESS
          : SYMBOLS.UI.DOWNLOAD)
    }

    $container
      .on('mouseenter.quickDownload', mouseEnterHandler)
      .on('mouseleave.quickDownload', mouseLeaveHandler)

    this.tracker.eventListeners($container, 'mouseenter.quickDownload', mouseEnterHandler)
    this.tracker.eventListeners($container, 'mouseleave.quickDownload', mouseLeaveHandler)
  }

  /**
   * 启动悬浮定时器
   */
  startHoverTimer(hoverTimer: number | null, $button: JQuery<Element> | null): number {
    this.stopHoverTimer(hoverTimer)

    return window.setTimeout(() => {
      $button
        ?.addClass('visible')
        .html(SYMBOLS.UI.DOWNLOAD)
    }, this.config.hoverDelay)
  }

  /**
   * 停止悬浮定时器
   */
  stopHoverTimer(hoverTimer: number | null): void {
    if (!hoverTimer)
      return

    clearTimeout(hoverTimer)
    hoverTimer = null
  }

  private async handleDownloadClick($button: JQuery<Element>, options: QuickDownloadOptions): Promise<void> {
    const { index, imageName, detailUrl } = options

    const downloadKey = `${detailUrl}-${index}`

    if (this.activeDownloads.has(downloadKey)) {
      logger.info(`[${this.name}] 下载正在进行中，请稍候`)
      return
    }

    this.activeDownloads.add(downloadKey)

    try {
      this.setButtonLoading($button, true)
      await this.triggerDownload(options)
      logger.info(`[${this.name}] 第 ${index + 1} 张图片下载完成`, { index, imageName, url: detailUrl })
    }
    catch (error: any) {
      logger.error(`[${this.name}] 下载失败`, error)
    }
    finally {
      this.activeDownloads.delete(downloadKey)
      this.setButtonLoading($button, false)
    }
  }

  /**
   * 设置下载按钮的加载状态
   */
  private setButtonLoading($button: JQuery<Element>, loading: boolean): void {
    if (loading) {
      $button
        .removeClass('downloaded')
        .addClass('loading')
        .html(SYMBOLS.STATUS.REFRESH)
    }
    else {
      $button
        .removeClass('loading')
        .addClass('downloaded')
        .html(SYMBOLS.STATUS.SUCCESS)
    }
  }

  /**
   * 触发下载
   */
  private async triggerDownload(options: QuickDownloadOptions): Promise<void> {
    const { index, detailUrl } = options
    logger.important(`[${this.name}] 触发下载第 ${index + 1} 张图片`)

    const config: DownloadTriggerConfig = {
      waitAfterClick: 500,
      downloadButtonSelector: this.currentConfig!.detailSelector.downloadButton,
      fetchConfig: this.config.fetchConfig,
      preClickCheck: ($button) => {
        // 检查按钮是否可用
        const isEnabled = !$button.prop('disabled')
        const hasHref = !!$button.attr('href')

        if (!isEnabled || !hasHref) {
          logger.warn(`[${this.name}] 下载按钮不可用`, {
            enabled: isEnabled,
            hasHref,
          })
          return false
        }
        return true
      },
      postClickAction: ($button) => {
        logger.debug(`[${this.name}] 下载按钮已点击`, {
          text: $button.text().trim(),
          href: $button.attr('href'),
        })
      },
    }

    const result = await this.downloadTrigger.triggerDownload(detailUrl, config)

    if (!result.success) {
      if (!result.data?.buttonFound)
        throw new Error('未找到下载按钮')

      throw result.error || new Error('触发下载失败')
    }

    if (result.data) {
      logger.debug(`[${this.name}] 下载触发成功`, {
        buttonText: result.data.buttonText,
        buttonHref: result.data.buttonHref,
      })
    }
  }

  applyConfig(config: Partial<Config>): void {
    super.updateConfig(config)

    this.applyToImages()

    logger.info(`[${this.name}] Config updated and apply`, this.config)
  }

  getStyles(): string {
    return `
/* 下载按钮 */
.${this.BUTTON_ID} {
  position: absolute;
  width: 32px;
  height: 32px;
  top: 10px;
  right: 10px;
  background: rgba(0, 0, 0, 0.7);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  border: none;
  cursor: pointer;
  pointer-events: auto;
  opacity: 0;
  transform: scale(0.8);
  transition: all 200ms ease;
  z-index: 1000;
  font-size: 16px;
  text-decoration: none;
  
  &:hover {
    background: rgba(0, 0, 0, 0.9);
    transform: scale(1.1);
  }
  
  &.loading {
    pointer-events: none;
    opacity: 1 !important;
  }
  
  &.downloaded {
    opacity: 1 !important;
    transform: scale(0.8);
  }
  
  &.visible {
    opacity: 1 !important;
    transform: scale(1);
  }
}
`
  }
}
